package com.edushare.common.dao.academics.grades;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.SelectQuery;

import com.edushare.common.dao.CayenneBasedDAO;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.vo.GradeKey;
import com.edushare.common.vo.Universities;

public class UnivLetterGrades extends CayenneBasedDAO {
	public static final int GRADEKEY_VERIFIED = 0;
	public static final int GRADEKEY_LOWERBOUND_ERR = 1;
	public static final int GRADEKEY_UPPERBOUND_ERR = 2;
	public static final int GRADEKEY_INCONSISTENT_ERR = 3;

	public static final String[] err = {
			"",
			"Warning : The minimum marks for lowest grade should be 0",
			"Warning : The maximum marks for highest grade should be 100",
			"Warning : The maximum marks for any grade should be less than minimum marks for next grade" };

	public UnivLetterGrades(ORMInterface ormInterface) {
		super(ormInterface);
	}

	public boolean hasLetterGrades(Universities univ) {
		if (getActiveVersion(univ) == -1)
			return false;
		return true;
	}

	public List<GradeKey> getUnivLetterGrades(Universities univ) {
		if (getActiveVersion(univ) == -1)
			return new ArrayList<GradeKey>();
		List<GradeKey> gkList = getSetOfGrades(univ, getLatestVersion(univ));
		Collections.sort(gkList);
		return gkList;
	}

	public void addLetterGrade(Universities univ, String gradeName,
			double gradeMarks, double max, double min, boolean pass) {
		int activeVersion = getActiveVersion(univ);
		if (activeVersion == -1) {
			activeVersion = getLatestVersion(univ) + 1;
		}
		GradeKey key = new GradeKey();
		key.setActive(GradeKey.ACTIVE_KEY);
		key.setEntityId(univ.getUniversityId());
		key.setEntityType(GradeKey.UNIVERSITY_KEY);
		key.setGradeAlphabet(gradeName);
		key.setGradeNumber(gradeMarks);
		key.setKeyVersion(activeVersion);
		key.setMaximumMarks(max);
		key.setMinimumMarks(min);
		key.setPass(pass);
		key.setParent(null);
		getDataContext().registerNewObject(key);
		getDataContext().commitChanges();
	}

	public int verifyIntegrity(List<GradeKey> gkList) {
		Collections.sort(gkList);
		if (gkList.size() != 0)
			return GRADEKEY_VERIFIED;
		GradeKey first = gkList.get(0);
		if (first.getMinimumMarks() > 0.01)
			return GRADEKEY_LOWERBOUND_ERR;
		GradeKey last = gkList.get(gkList.size() - 1);
		if (last.getMinimumMarks() < 99.9)
			return GRADEKEY_LOWERBOUND_ERR;
		for (int i = 0; i < gkList.size() - 1; i++) {
			if (gkList.get(i).getMaximumMarks() > gkList.get(i)
					.getMinimumMarks())
				return GRADEKEY_INCONSISTENT_ERR;
		}
		return GRADEKEY_VERIFIED;
	}

	public void editLetterGrade(GradeKey k, String alphabet, double gradeNum,
			double max, double min) {
		k.setGradeAlphabet(alphabet);
		k.setGradeNumber(gradeNum);
		k.setMaximumMarks(max);
		k.setMinimumMarks(min);
		getDataContext().commitChanges();
	}

	public void removeChildren(GradeKey k){
		List<GradeKey> children = k.getChildren();
		for(GradeKey child:children){
			removeGrade(child);
		}
	}
	
	public void removeGrade(GradeKey k){
		k.setActive(GradeKey.INACTIVE_KEY);
		removeChildren(k);
		getDataContext().commitChanges();
	}

	public void discardCurrentSet(Universities univ) {
		List<GradeKey> gkList = getSetOfGrades(univ, getLatestVersion(univ));
		for (GradeKey gk : gkList) {
			removeGrade(gk);
		}
		getDataContext().commitChanges();
	}
	
	@SuppressWarnings("unchecked")
	public int getActiveVersion(Universities univ) {
		Expression exp = Expression
				.fromString("entityId = $entityId and entityType = $entityType");
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("entityId", univ.getUniversityId());
		map.put("entityType", GradeKey.UNIVERSITY_KEY);
		SelectQuery q = new SelectQuery(GradeKey.class, exp
				.expWithParameters(map));
		List<GradeKey> gkList = getDataContext().performQuery(q);
		int version = -1;
		for (GradeKey gk : gkList) {
			if (gk.getActive() == GradeKey.ACTIVE_KEY)
				version = gk.getKeyVersion();
		}
		return version;
	}

	@SuppressWarnings("unchecked")
	public List<GradeKey> getSetOfGrades(Universities univ, int version) {
		Expression exp = Expression.fromString("entityId = $entityId "
				+ "and entityType = $entityType and keyVersion = $keyVersion");
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("entityId", univ.getUniversityId());
		map.put("entityType", GradeKey.UNIVERSITY_KEY);
		map.put("keyVersion", version);
		SelectQuery q = new SelectQuery(GradeKey.class, exp
				.expWithParameters(map));
		List<GradeKey> gkList = getDataContext().performQuery(q);
		return gkList;
	}

	@SuppressWarnings("unchecked")
	public int getLatestVersion(Universities univ) {
		Expression exp = Expression
				.fromString("entityId = $entityId and entityType = $entityType");
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		map.put("entityId", univ.getUniversityId());
		map.put("entityType", GradeKey.UNIVERSITY_KEY);
		SelectQuery q = new SelectQuery(GradeKey.class, exp
				.expWithParameters(map));
		List<GradeKey> gkList = getDataContext().performQuery(q);
		int version = -1;
		for (GradeKey gk : gkList) {
			if (gk.getKeyVersion() > version)
				version = gk.getKeyVersion();
		}
		return version;
	}
}
